<?php
namespace Tyrone\Lib;
use Medoo\Medoo;

class SafeMedoo extends Medoo
{
    private $pool;
    private $retries;

    public function __construct($options, $pool,$retries=3)
    {
        parent::__construct($options);
        $this->pool = $pool;
        $this->retries = $retries;
    }


    private function isDisconnected(\PDOException $e)
    {
        return in_array($e->getCode(), [2006, 2013, 2054])
            || strpos($e->getMessage(), 'gone away') !== false;
    }

    private function reconnect()
    {
        $newConn = $this->pool->createConnection();
        $this->pdo = $newConn->pdo;
        $this->queryString = null;
    }

    public function exec($query, $map = [])
    {
        try{
            $return = parent::exec($query, $map);
            if(APP_DEBUG){
                file_put_contents(DIR.'/runtime/mysql_'.date('Ymd').'.log',$this->last());
            }
        }catch (\Throwable $exception){
            for ($i = 0; $i <= $this->retries; $i++) {
                try {
                    $return = parent::exec($query, $map);
                } catch (\PDOException $e) {
                    if ($this->isDisconnected($e) && $i < $this->retries) {
                        $this->reconnect();
                        \Swoole\Coroutine::sleep(0.01);
                        continue;
                    }
                    throw $e;
                }
            }
        }
        return $return ?? null;
    }

    protected function tableQuote($table)
    {
        $db_prefix = '';
        $tableInfo = explode('.',$table);
        if(($tableInfo[0]?? '') &&($tableInfo[1]?? '')){
            $table = $tableInfo[1];
            $db_prefix = $tableInfo[0].'.';
        }
        return $db_prefix.parent::tableQuote($table);
    }

    public function getDbName(){
        return $this->dsn;
    }

    public function updateOrInsert($table,$row, $unique = [])
    {
        if (empty($row)) {
            return false; // 确保传入的数据和唯一字段不为空
        }
        if(!$unique){
            return $this->insert($table,$row);
        }

        // 构造 INSERT 部分
        $keys = implode(',', array_keys($row));
        $values = "'" . implode("','", array_values($row)) . "'";

        // 构造 ON DUPLICATE KEY UPDATE 部分
        $updateFields = [];
        foreach ($row as $key => $value) {
            if (!in_array($key, $unique)) { // 唯一字段不需要更新
                $updateFields[] = "`{$key}` = VALUES(`{$key}`)";
            }
        }
        $updateClause = implode(', ', $updateFields);

        // 构造完整的 SQL 语句
        $sql = "INSERT INTO {$table} ({$keys}) VALUES ({$values}) ON DUPLICATE KEY UPDATE {$updateClause}";

        // 执行 SQL
        return $this->query($sql);
    }

    public function batchUpdateOrInsert($table, $rows, $unique = []){
        if (empty($rows)) {
            return false; // 确保传入的数据和唯一字段不为空
        }
        if(!$unique){
            return $this->insert($table,$rows);
        }

        // 构造 INSERT 部分
        $keys = implode(',', array_keys($rows[0]));
        $values = [];
        foreach ($rows as $row){
            $values[] = '(\''.implode("','", array_values($row)).'\')';
        }
        $valueStr = implode(',',$values);
        // 构造 ON DUPLICATE KEY UPDATE 部分
        $updateFields = [];
        foreach ($rows[0] as $key => $value) {
            if (!in_array($key, $unique)) { // 唯一字段不需要更新
                $updateFields[] = "`{$key}` = VALUES(`{$key}`)";
            }
        }
        $updateClause = implode(', ', $updateFields);

        // 构造完整的 SQL 语句
        $sql = "INSERT INTO {$table} ({$keys}) VALUES {$valueStr} ON DUPLICATE KEY UPDATE {$updateClause}";
        return $this->query($sql);
    }

}